#include "filesystem.h"

// 初始化文件系统
void init_filesystem(FileSystem *fs) {
    // 初始化所有数据结构
    memset(fs, 0, sizeof(FileSystem));
    
    // 初始化空闲块位图，全部设为可用（1表示空闲）
    for (int i = 0; i < MAX_BLOCKS; i++) {
        fs->free_block_map[i] = 1;
        fs->free_inode_map[i] = 1;
    }
    
    // 创建根目录
    int root_inode = allocate_inode(fs);
    if (root_inode != -1) {
        fs->inodes[root_inode].inode_id = root_inode;
        fs->inodes[root_inode].type = DIR_TYPE;
        fs->inodes[root_inode].size = 0;
        fs->inodes[root_inode].create_time = time(NULL);
        fs->inodes[root_inode].modify_time = time(NULL);
        
        // 初始化根目录项（.和..）
        strcpy(fs->root_dir[0].name, ".");
        fs->root_dir[0].inode_id = root_inode;
        fs->root_dir[0].type = DIR_TYPE;
        
        strcpy(fs->root_dir[1].name, "..");
        fs->root_dir[1].inode_id = root_inode;  // 根目录的父目录还是自己
        fs->root_dir[1].type = DIR_TYPE;
        
        fs->inodes[root_inode].size += 2 * sizeof(DirEntry);
        fs->current_inode = root_inode;
    }
    
    printf("文件系统初始化完成\n");
}

// 分配磁盘块
int allocate_block(FileSystem *fs) {
    for (int i = 0; i < MAX_BLOCKS; i++) {
        if (fs->free_block_map[i]) {
            fs->free_block_map[i] = 0;  // 标记为已使用
            return i;
        }
    }
    return -1;  // 没有可用块
}

// 分配索引节点
int allocate_inode(FileSystem *fs) {
    for (int i = 0; i < MAX_BLOCKS; i++) {
        if (fs->free_inode_map[i]) {
            fs->free_inode_map[i] = 0;  // 标记为已使用
            return i;
        }
    }
    return -1;  // 没有可用inode
}

// 释放磁盘块
void free_block(FileSystem *fs, int block_id) {
    if (block_id >= 0 && block_id < MAX_BLOCKS) {
        fs->free_block_map[block_id] = 1;
    }
}

// 释放索引节点
void free_inode(FileSystem *fs, int inode_id) {
    if (inode_id >= 0 && inode_id < MAX_BLOCKS) {
        fs->free_inode_map[inode_id] = 1;
    }
}

// 根据名称查找索引节点
int get_inode_by_name(FileSystem *fs, const char *name, DirEntry *entries, int entry_count) {
    for (int i = 0; i < entry_count; i++) {
        if (strcmp(entries[i].name, name) == 0) {
            return entries[i].inode_id;
        }
    }
    return -1;  // 未找到
}

// 创建文件
int create_file(FileSystem *fs, const char *name) {
    // 检查文件名是否已存在
    if (get_inode_by_name(fs, name, fs->root_dir, MAX_DIR_ENTRIES) != -1) {
        printf("文件 %s 已存在\n", name);
        return -1;
    }
    
    // 分配inode
    int inode_id = allocate_inode(fs);
    if (inode_id == -1) {
        printf("没有可用的索引节点\n");
        return -1;
    }
    
    // 初始化inode
    fs->inodes[inode_id].inode_id = inode_id;
    fs->inodes[inode_id].type = FILE_TYPE;
    fs->inodes[inode_id].size = 0;
    fs->inodes[inode_id].create_time = time(NULL);
    fs->inodes[inode_id].modify_time = time(NULL);
    memset(fs->inodes[inode_id].blocks, -1, sizeof(fs->inodes[inode_id].blocks));
    
    // 添加到目录
    for (int i = 0; i < MAX_DIR_ENTRIES; i++) {
        if (fs->root_dir[i].name[0] == '\0') {
            strcpy(fs->root_dir[i].name, name);
            fs->root_dir[i].inode_id = inode_id;
            fs->root_dir[i].type = FILE_TYPE;
            fs->inodes[fs->current_inode].size += sizeof(DirEntry);
            printf("文件 %s 创建成功\n", name);
            return 0;
        }
    }
    
    // 目录已满，释放inode
    free_inode(fs, inode_id);
    printf("目录已满，无法创建文件\n");
    return -1;
}

// 创建目录
int create_dir(FileSystem *fs, const char *name) {
    // 检查目录名是否已存在
    if (get_inode_by_name(fs, name, fs->root_dir, MAX_DIR_ENTRIES) != -1) {
        printf("目录 %s 已存在\n", name);
        return -1;
    }
    
    // 分配inode
    int inode_id = allocate_inode(fs);
    if (inode_id == -1) {
        printf("没有可用的索引节点\n");
        return -1;
    }
    
    // 初始化inode
    fs->inodes[inode_id].inode_id = inode_id;
    fs->inodes[inode_id].type = DIR_TYPE;
    fs->inodes[inode_id].size = 2 * sizeof(DirEntry);  // .和..
    fs->inodes[inode_id].create_time = time(NULL);
    fs->inodes[inode_id].modify_time = time(NULL);
    
    // 分配一个数据块来存储目录项
    int block_id = allocate_block(fs);
    if (block_id == -1) {
        free_inode(fs, inode_id);
        printf("没有可用的磁盘块\n");
        return -1;
    }
    fs->inodes[inode_id].blocks[0] = block_id;
    
    // 初始化目录项
    DirEntry *entries = (DirEntry *)fs->blocks[block_id].data;
    strcpy(entries[0].name, ".");
    entries[0].inode_id = inode_id;
    entries[0].type = DIR_TYPE;
    
    strcpy(entries[1].name, "..");
    entries[1].inode_id = fs->current_inode;  // 父目录是当前目录
    entries[1].type = DIR_TYPE;
    
    // 添加到父目录
    for (int i = 0; i < MAX_DIR_ENTRIES; i++) {
        if (fs->root_dir[i].name[0] == '\0') {
            strcpy(fs->root_dir[i].name, name);
            fs->root_dir[i].inode_id = inode_id;
            fs->root_dir[i].type = DIR_TYPE;
            fs->inodes[fs->current_inode].size += sizeof(DirEntry);
            printf("目录 %s 创建成功\n", name);
            return 0;
        }
    }
    
    // 清理资源
    free_block(fs, block_id);
    free_inode(fs, inode_id);
    printf("父目录已满，无法创建目录\n");
    return -1;
}

// 打开文件
int open_file(FileSystem *fs, const char *name, int flags) {
    // 查找文件
    int inode_id = get_inode_by_name(fs, name, fs->root_dir, MAX_DIR_ENTRIES);
    if (inode_id == -1) {
        printf("文件 %s 不存在\n", name);
        return -1;
    }
    
    // 检查是否是文件类型
    if (fs->inodes[inode_id].type != FILE_TYPE) {
        printf("%s 不是一个文件\n", name);
        return -1;
    }
    
    // 查找空闲的文件描述符
    for (int i = 0; i < MAX_OPEN_FILES; i++) {
        if (!fs->open_files[i].valid) {
            fs->open_files[i].inode_id = inode_id;
            fs->open_files[i].offset = 0;
            fs->open_files[i].flags = flags;
            fs->open_files[i].valid = 1;
            printf("文件 %s 打开成功，文件描述符: %d\n", name, i);
            return i;
        }
    }
    
    printf("打开的文件数已达上限\n");
    return -1;
}

// 关闭文件
int close_file(FileSystem *fs, int fd) {
    if (fd >= 0 && fd < MAX_OPEN_FILES && fs->open_files[fd].valid) {
        fs->open_files[fd].valid = 0;
        printf("文件描述符 %d 已关闭\n", fd);
        return 0;
    }
    printf("无效的文件描述符\n");
    return -1;
}

// 写入文件
int write_file(FileSystem *fs, int fd, const char *buffer, int size) {
    if (fd < 0 || fd >= MAX_OPEN_FILES || !fs->open_files[fd].valid) {
        printf("无效的文件描述符\n");
        return -1;
    }
    
    if (fs->open_files[fd].flags == 0) {  // 只读模式
        printf("文件以只读模式打开，无法写入\n");
        return -1;
    }
    
    int inode_id = fs->open_files[fd].inode_id;
    int offset = fs->open_files[fd].offset;
    int bytes_written = 0;
    
    while (bytes_written < size) {
        int block_index = offset / BLOCK_SIZE;
        int block_offset = offset % BLOCK_SIZE;
        int bytes_to_write = BLOCK_SIZE - block_offset;
        if (bytes_to_write > size - bytes_written) {
            bytes_to_write = size - bytes_written;
        }
        
        // 检查是否需要分配新块
        if (fs->inodes[inode_id].blocks[block_index] == -1) {
            fs->inodes[inode_id].blocks[block_index] = allocate_block(fs);
            if (fs->inodes[inode_id].blocks[block_index] == -1) {
                printf("没有可用的磁盘块\n");
                return bytes_written;  // 返回已写入的字节数
            }
        }
        
        int block_id = fs->inodes[inode_id].blocks[block_index];
        memcpy(fs->blocks[block_id].data + block_offset, buffer + bytes_written, bytes_to_write);
        
        bytes_written += bytes_to_write;
        offset += bytes_to_write;
    }
    
    // 更新文件大小和偏移量
    if (offset > fs->inodes[inode_id].size) {
        fs->inodes[inode_id].size = offset;
    }
    fs->open_files[fd].offset = offset;
    fs->inodes[inode_id].modify_time = time(NULL);
    
    printf("成功写入 %d 字节\n", bytes_written);
    return bytes_written;
}

// 读取文件
int read_file(FileSystem *fs, int fd, char *buffer, int size) {
    if (fd < 0 || fd >= MAX_OPEN_FILES || !fs->open_files[fd].valid) {
        printf("无效的文件描述符\n");
        return -1;
    }
    
    int inode_id = fs->open_files[fd].inode_id;
    int offset = fs->open_files[fd].offset;
    
    // 检查是否已到达文件末尾
    if (offset >= fs->inodes[inode_id].size) {
        return 0;  // 已到达文件末尾
    }
    
    // 计算实际可读取的字节数
    int bytes_to_read = size;
    if (offset + size > fs->inodes[inode_id].size) {
        bytes_to_read = fs->inodes[inode_id].size - offset;
    }
    
    int bytes_read = 0;
    
    while (bytes_read < bytes_to_read) {
        int block_index = offset / BLOCK_SIZE;
        int block_offset = offset % BLOCK_SIZE;
        int bytes_available = BLOCK_SIZE - block_offset;
        int bytes_to_read_now = bytes_available;
        if (bytes_to_read_now > bytes_to_read - bytes_read) {
            bytes_to_read_now = bytes_to_read - bytes_read;
        }
        
        // 检查块是否存在
        if (fs->inodes[inode_id].blocks[block_index] == -1) {
            break;  // 块不存在，结束读取
        }
        
        int block_id = fs->inodes[inode_id].blocks[block_index];
        memcpy(buffer + bytes_read, fs->blocks[block_id].data + block_offset, bytes_to_read_now);
        
        bytes_read += bytes_to_read_now;
        offset += bytes_to_read_now;
    }
    
    // 更新偏移量
    fs->open_files[fd].offset = offset;
    
    printf("成功读取 %d 字节\n", bytes_read);
    return bytes_read;
}

// 删除文件
int delete_file(FileSystem *fs, const char *name) {
    // 查找文件在目录中的位置
    int file_index = -1;
    for (int i = 0; i < MAX_DIR_ENTRIES; i++) {
        if (strcmp(fs->root_dir[i].name, name) == 0) {
            file_index = i;
            break;
        }
    }
    
    if (file_index == -1) {
        printf("文件 %s 不存在\n", name);
        return -1;
    }
    
    // 检查是否是目录
    if (fs->root_dir[file_index].type == DIR_TYPE) {
        printf("无法删除目录，请使用专门的删除目录函数\n");
        return -1;
    }
    
    // 检查文件是否已打开
    for (int i = 0; i < MAX_OPEN_FILES; i++) {
        if (fs->open_files[i].valid && fs->open_files[i].inode_id == fs->root_dir[file_index].inode_id) {
            printf("文件 %s 正在使用中，无法删除\n", name);
            return -1;
        }
    }
    
    int inode_id = fs->root_dir[file_index].inode_id;
    
    // 释放文件占用的块
    for (int i = 0; i < 10 && fs->inodes[inode_id].blocks[i] != -1; i++) {
        free_block(fs, fs->inodes[inode_id].blocks[i]);
    }
    
    // 释放inode
    free_inode(fs, inode_id);
    
    // 从目录中删除
    fs->root_dir[file_index].name[0] = '\0';
    fs->inodes[fs->current_inode].size -= sizeof(DirEntry);
    
    printf("文件 %s 删除成功\n", name);
    return 0;
}

// 列出目录内容
int list_dir(FileSystem *fs, const char *dir_name) {
    DirEntry *entries = fs->root_dir;
    int entry_count = MAX_DIR_ENTRIES;
    
    if (strcmp(dir_name, ".") != 0 && strcmp(dir_name, "") != 0) {
        // 查找指定目录
        int inode_id = get_inode_by_name(fs, dir_name, fs->root_dir, MAX_DIR_ENTRIES);
        if (inode_id == -1) {
            printf("目录 %s 不存在\n", dir_name);
            return -1;
        }
        
        if (fs->inodes[inode_id].type != DIR_TYPE) {
            printf("%s 不是一个目录\n", dir_name);
            return -1;
        }
        
        // 获取目录的块
        if (fs->inodes[inode_id].blocks[0] != -1) {
            entries = (DirEntry *)fs->blocks[fs->inodes[inode_id].blocks[0]].data;
        }
    }
    
    printf("目录内容:\n");
    printf("%-20s %-10s %-15s %s\n", "名称", "类型", "大小", "修改时间");
    
    for (int i = 0; i < entry_count; i++) {
        if (entries[i].name[0] != '\0') {
            int inode_id = entries[i].inode_id;
            char type_str[10];
            if (entries[i].type == FILE_TYPE) {
                strcpy(type_str, "文件");
            } else {
                strcpy(type_str, "目录");
            }
            
            char time_str[64];
            strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&fs->inodes[inode_id].modify_time));
            
            printf("%-20s %-10s %-15d %s\n", 
                   entries[i].name, 
                   type_str, 
                   fs->inodes[inode_id].size, 
                   time_str);
        }
    }
    
    return 0;
}

// 切换目录
int change_dir(FileSystem *fs, const char *dir_name) {
    if (strcmp(dir_name, ".") == 0) {
        return 0;  // 当前目录，无需切换
    }
    
    if (strcmp(dir_name, "..") == 0) {
        // 对于简单版本，我们只允许在根目录下操作
        printf("当前版本仅支持在根目录下操作\n");
        return -1;
    }
    
    // 查找目录
    int inode_id = get_inode_by_name(fs, dir_name, fs->root_dir, MAX_DIR_ENTRIES);
    if (inode_id == -1) {
        printf("目录 %s 不存在\n", dir_name);
        return -1;
    }
    
    if (fs->inodes[inode_id].type != DIR_TYPE) {
        printf("%s 不是一个目录\n", dir_name);
        return -1;
    }
    
    printf("切换到目录 %s\n", dir_name);
    // 注意：在简单版本中，我们不会真正切换目录，只是显示成功信息
    return 0;
}

// 格式化文件系统
void format_filesystem(FileSystem *fs) {
    printf("格式化文件系统...\n");
    init_filesystem(fs);
    printf("文件系统格式化完成\n");
}